package mvp.hibernate.demo.util;

import mvp.hibernate.demo.model.Money;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.type.BasicType;
import org.hibernate.type.BigDecimalType;
import org.hibernate.type.CurrencyType;
import org.hibernate.usertype.UserType;

import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Currency;

/**
 * Created by user on 13.07.14.
 */

public class MoneyType implements UserType {

    @Override
    public int[] sqlTypes() {
        return new int[]{
                BigDecimalType.INSTANCE.sqlType(),
                CurrencyType.INSTANCE.sqlType(),
        };
    }

    @Override
    public Class returnedClass() {
        return Money.class;
    }

    @Override
    public boolean equals(Object o, Object o2) throws HibernateException {
        return o.equals(o2);
    }

    @Override
    public int hashCode(Object o) throws HibernateException {
        return o.hashCode();
    }

    public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws SQLException {
        assert names.length == 2;
        BigDecimal amount = (BigDecimal) BigDecimalType.INSTANCE.get(rs, names[0], session); // already handles null check
        Currency currency = (Currency) CurrencyType.INSTANCE.get(rs, names[1], session); // already handles null check
        return amount == null && currency == null
                ? null
                : new Money(amount, currency);
    }

    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException {
        if (value == null) {
            BigDecimalType.INSTANCE.set(st, null, index, session);
            CurrencyType.INSTANCE.set(st, null, index + 1, session);
        } else {
            final Money money = (Money) value;
            BigDecimalType.INSTANCE.set(st, money.getAmount(), index, session);
            CurrencyType.INSTANCE.set(st, money.getCurrency(), index + 1, session);
        }
    }

    @Override
    public Object deepCopy(Object o) throws HibernateException {
        return new Money(((Money) o).getAmount(), ((Money) o).getCurrency());
    }

    @Override
    public boolean isMutable() {
        return true;
    }

    @Override
    public Serializable disassemble(Object o) throws HibernateException {
        return (Serializable)o;
    }

    @Override
    public Object assemble(Serializable serializable, Object o) throws HibernateException {
        return (Serializable)o;
    }

    @Override
    public Object replace(Object o, Object o2, Object o3) throws HibernateException {
        return o;
    }
}

